package com.falcon.service.impl;

import com.falcon.config.GeneratorConfig;
import com.falcon.core.enums.ResponseCodeEnum;
import com.falcon.core.utils.AssertUtil;
import com.falcon.service.IDomainMetaService;
import com.falcon.domain.req.DomainMetaQuery;
import com.falcon.domain.vo.DomainMeta;
import com.swan.core.utils.ClassUtil;
import com.swan.core.utils.TxtFileUtil;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zongf
 * @date 2024-03-16
 **/
@Slf4j
@Service
public class DomainMetaService implements IDomainMetaService {

    @Autowired
    private GeneratorConfig generatorConfig;

    private List<DomainMeta> metaList = null;


    @Override
    public List<DomainMeta> doScan() {
        String domainPackage = generatorConfig.getPackageName() + ".domain";

        List<DomainMeta> domainMetas = new ArrayList<>();

        String domainPath = domainPackage.replaceAll("\\.", "/");
        try {
            Enumeration<URL> resources = ClassLoader.getSystemClassLoader().getResources(domainPath);

            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                File file = new File(url.getFile());
                System.out.println(file.getAbsolutePath());
                deepList(file, domainPackage, domainMetas);
            }
        } catch (Throwable ex) {
            log.error("检索资源异常");
            AssertUtil.throwException(ResponseCodeEnum.GEN,"检索资源异常");
        }

        return domainMetas;
    }

    @Override
    public List<DomainMeta> list(DomainMetaQuery request) {

        metaList = doScan();

        return metaList.stream()
                .filter(domain ->{
                    boolean math = true;
                    if (StringUtils.isNotEmpty(request.getName())) {
                        math &= domain.getName().toUpperCase().contains(request.getName().toUpperCase());
                    }
                    if (StringUtils.isNotEmpty(request.getType())) {
                        math &= domain.getType().toUpperCase().contains(request.getType().toUpperCase());
                    }
                    return math;
                })
                .sorted(Comparator.comparing(DomainMeta::getName))
                .collect(Collectors.toList());
    }

    private void deepList(File file, String parentPackage,List<DomainMeta> metaList) {
        if (file.isDirectory()) {
            File[] subFiles = file.listFiles();
            for (File subFile : subFiles) {
                if (!parentPackage.endsWith(file.getName())) {
                    parentPackage += "." + file.getName();
                }
                deepList(subFile,parentPackage , metaList);
            }
        }else {
            DomainMeta domainMeta = new DomainMeta();
            domainMeta.setName(StringUtils.substringBefore(file.getName(),"."));
            domainMeta.setCanonicalName(parentPackage + "." + domainMeta.getName());
            domainMeta.setType(StringUtils.substringAfterLast(parentPackage,"."));
            domainMeta.setDescription(this.getDomainDescription(domainMeta.getCanonicalName()));
            domainMeta.setSource(getFileSource(file.getAbsolutePath()));

            // 添加时，排除lombok生成的 Fields 类
            if (!domainMeta.getName().endsWith("$Fields")) {
                metaList.add(domainMeta);
            }
        }
    }

    private String getFileSource(String filePath) {
        String servicesPath = StringUtils.substringBefore(filePath, "falcon-all-services");
        String fileRelativePath = "/src/main/java" + StringUtils.substringAfter(filePath, "target/classes").replace(".class", ".java");
        File servicesDir = new File(servicesPath);
        for (File file : servicesDir.listFiles()) {
            File classFile = new File(file.getAbsolutePath() + fileRelativePath);
            if (classFile.exists()) {
                return TxtFileUtil.readFileContent(classFile.getAbsolutePath());
            }
        }
        return null;
    }

    private String getDomainDescription(String className){
        Class clz = ClassUtil.forName(className, this.getClass().getClassLoader());

        if (Objects.nonNull(clz) && clz.isAnnotationPresent(Tag.class)) {
            Tag tag = (Tag) clz.getAnnotation(Tag.class);
            return tag.name();
        }

        return null;
    }


}
